package com.tanxi521.tnlevel.dao;

import com.tanxi521.tnlevel.TnLevel;
import com.tanxi521.tnlevel.listener.TnLevelListener;
import com.tanxi521.tnlevel.pojo.PlayerLevel;
import com.tanxi521.tnlevel.utils.ConfigReader;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: i-xiaotian
 * @Date: 2022/3/13 5:49
 * @EMAIL: 1254806967@qq.com
 */
public class SQLManager {

    public static void createTable() {
        Connection connection = ConnectionPool.getConnection();
        PreparedStatement statement = null;
        try {
            assert connection != null;
            if (ConfigReader.getMysqlUse()) {
                statement = connection.prepareStatement(SQLStatement.CREATE_TABLE_MYSQL.getStatement());
                statement.execute();
            } else {
                statement = connection.prepareStatement(SQLStatement.CREATE_TABLE_SQLITE.getStatement());
                statement.execute();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                ConnectionPool.returnSource(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static PlayerLevel getPlayerLevel(Player p) {
        String displayName = p.getName();
        return gerPlayerLevelByName(displayName);
    }

    public static PlayerLevel gerPlayerLevelByName(String playerName) {
        Connection connection = ConnectionPool.getConnection();
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        PlayerLevel playerLevel = new PlayerLevel();
        try {
            if (connection != null) {
                statement = connection.prepareStatement(SQLStatement.SELECT_PLAYER.getStatement());
                statement.setString(1, playerName);
                resultSet = statement.executeQuery();
                if (!resultSet.next()) {
                    return new PlayerLevel();
                }
                playerLevel.setId(resultSet.getInt("id"))
                        .setUuid(resultSet.getString("player_uuid"))
                        .setDisplayName(resultSet.getString("display_name"))
                        .setPlayerLevel(resultSet.getInt("player_level"))
                        .setPlayerExp(resultSet.getLong("player_exp"))
                        .setPlayerExpToNextLevel(resultSet.getLong("player_exp_to_next_level"))
                        .setPlayerTotalExp(resultSet.getLong("player_total_exp"))
                        .setGMTCreate(resultSet.getLong("gmt_create"))
                        .setGMTUpdate(resultSet.getLong("gmt_update"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                if (resultSet != null) resultSet.close();
                ConnectionPool.returnSource(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return playerLevel;
    }

    public static PlayerLevel gerPlayerLevelByUuid(String uuid) {
        Connection connection = ConnectionPool.getConnection();
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        PlayerLevel playerLevel = new PlayerLevel();
        try {
            if (connection != null) {
                statement = connection.prepareStatement(SQLStatement.SELECT_PLAYER_BY_UUID.getStatement());
                statement.setString(1, uuid);
                resultSet = statement.executeQuery();
                if (!resultSet.next()) {
                    return new PlayerLevel();
                }
                playerLevel.setId(resultSet.getInt("id"))
                        .setUuid(resultSet.getString("player_uuid"))
                        .setDisplayName(resultSet.getString("display_name"))
                        .setPlayerLevel(resultSet.getInt("player_level"))
                        .setPlayerExp(resultSet.getLong("player_exp"))
                        .setPlayerExpToNextLevel(resultSet.getLong("player_exp_to_next_level"))
                        .setPlayerTotalExp(resultSet.getLong("player_total_exp"))
                        .setGMTCreate(resultSet.getLong("gmt_create"))
                        .setGMTUpdate(resultSet.getLong("gmt_update"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                if (resultSet != null) resultSet.close();
                ConnectionPool.returnSource(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return playerLevel;
    }

    public static void UpdatePlayer(PlayerLevel playerLevel) {
        Connection connection = ConnectionPool.getConnection();
        PreparedStatement statement = null;
        try {
            if (connection != null) {
                statement = connection.prepareStatement(SQLStatement.UPDATE_PLAYER.getStatement());
                statement.setInt(1, playerLevel.getPlayerLevel());
                statement.setLong(2, playerLevel.getPlayerExp());
                statement.setLong(3, playerLevel.getPlayerExpToNextLevel());
                statement.setLong(4, playerLevel.getPlayerTotalExp());
                statement.setLong(5, System.currentTimeMillis());
                statement.setString(6, playerLevel.getDisplayName());
                statement.execute();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                ConnectionPool.returnSource(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void insertPlayer(Player p) {
        Connection connection = ConnectionPool.getConnection();
        PlayerLevel playerLevel = new PlayerLevel();
        Long exp = TnLevelListener.levels.get(0);
        playerLevel.setUuid(p.getUniqueId().toString())
                .setDisplayName(p.getName())
                .setPlayerLevel(0)
                .setPlayerExp(0L)
                .setPlayerExpToNextLevel(exp)
                .setPlayerTotalExp(0L)
                .setGMTCreate(System.currentTimeMillis())
                .setGMTUpdate(System.currentTimeMillis());
        PreparedStatement statement = null;
        try {
            assert connection != null;
            statement = connection.prepareStatement(ConfigReader.getMysqlUse() ? SQLStatement.INSERT_ONE.getStatement()
                    : SQLStatement.INSERT_TWO.getStatement());
            statement.setString(1, playerLevel.getUuid());
            statement.setString(2, playerLevel.getDisplayName());
            statement.setInt(3, playerLevel.getPlayerLevel());
            statement.setLong(4, playerLevel.getPlayerExp());
            statement.setLong(5, playerLevel.getPlayerExpToNextLevel());
            statement.setLong(6, playerLevel.getPlayerTotalExp());
            statement.setLong(7, playerLevel.getGMTCreate());
            statement.setLong(8, playerLevel.getGMTUpdate());
            statement.setString(9, playerLevel.getDisplayName());
            statement.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                ConnectionPool.returnSource(connection);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static int selectCount() {
        Connection connection = ConnectionPool.getConnection();
        PreparedStatement statement = null;
        int count = 0;
        try {
            assert connection != null;
            statement = connection.prepareStatement(SQLStatement.SELECT_COUNT.getStatement());
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) count = resultSet.getInt(1);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                ConnectionPool.returnSource(connection);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        return count;
    }

    public static List<PlayerLevel> selectTopList(int start, int perPage) {
        Connection connection = ConnectionPool.getConnection();
        PreparedStatement statement = null;
        ResultSet rs = null;
        ArrayList<PlayerLevel> playerLevels = new ArrayList<>();
        try {
            assert connection != null;
            statement = connection.prepareStatement(SQLStatement.SELECT_TOP.getStatement());
            statement.setInt(1, start);
            statement.setInt(2, perPage);
            rs = statement.executeQuery();
            while (rs.next()) {
                PlayerLevel playerLevel = new PlayerLevel();
                playerLevel.setId(rs.getInt("id"));
                playerLevel.setUuid(rs.getString("player_uuid"));
                playerLevel.setDisplayName(rs.getString("display_name"));
                playerLevel.setPlayerLevel(rs.getInt("player_level"));
                playerLevel.setPlayerExp(rs.getLong("player_exp"));
                playerLevel.setPlayerExpToNextLevel(rs.getLong("player_exp_to_next_level"));
                playerLevel.setPlayerTotalExp(rs.getLong("player_total_exp"));
                playerLevel.setGMTCreate(rs.getLong("gmt_create"));
                playerLevel.setGMTUpdate(rs.getLong("gmt_update"));
                playerLevels.add(playerLevel);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                if (statement != null) statement.close();
                if (rs != null) rs.close();
                ConnectionPool.returnSource(connection);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        return playerLevels;
    }

    public static void batchUpdatePlayer(final List<PlayerLevel> playerLevels) {
        Bukkit.getScheduler().runTask(TnLevel.getInstance(), () -> {
            TnLevel.getInstance().getLogger().info("即将保存全部在线玩家等级数据...");
            final long start = System.currentTimeMillis();
            playerLevels.forEach(SQLManager::UpdatePlayer);
            final long end = System.currentTimeMillis() - start;
            TnLevel.getInstance().getLogger().info("在线玩家等级数据保存完成,耗时" + end + "ms");
        });
    }
}
